﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Threading;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.UI;
using Emgu.Util;
using Emgu.Util.TypeEnum;
using Scanning;
using ZedGraph;
using com.google.zxing;
using com.google.zxing.common;
using com.google.zxing.multi;

namespace FuseBoxInspector
{
    public partial class Form1 : Form
    {
        private const int MODE_OPEN_CAMERA = int.MaxValue - 1;
        private const int MODE_CAPTURE = int.MaxValue - 2;
        private const int MMODE_CAPTURE = int.MaxValue - 2; // my modify
        private const string DIR_SETTINGS = @"C:\fuseboxes\";
        private const string FILE_SETTINGS = DIR_SETTINGS + @"{0}.txt";

        private DataTable fuseTable;

        private Rectangle currentRect;
        private Inspector inspector;
        private int mode;
        private int mmode;      // my modify

        private Image select_img = null;

        private Point startPoint = new Point(-1, -1);
        private Point S_Point = new Point(-1, -1);
        private Point E_point = new Point(-1, -1);
        private Image origBitmap = null;

        private Image<Bgr, byte> BBitmap = null;

        private Thread camThread = null;
        private bool running = false;

        public Form1()
        {
            this.mode = MODE_CAPTURE;
            this.mmode = MODE_OPEN_CAMERA;
            InitializeComponent();
            initEngines();

            this.fuseTable = new DataTable("Detail");
            this.fuseTable.Columns.Add("Position");
            this.fuseTable.Columns.Add("Color");
            this.fuseTable.Columns.Add("Ampere");

            this.dgRectangles.DataSource = this.fuseTable;
            refreshModels();
            
            
            //this.zedgHue.GraphPane.Title.Text = "Hue";
            //this.zedgHue.GraphPane.XAxis.Title.Text = "Color Space";
            //this.zedgHue.GraphPane.YAxis.Title.Text = "Value";
          
        }

        private void initEngines()
        {
            this.inspector = new Inspector();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            startLabelMode();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
        }

        private void mnTraining_Click(object sender, EventArgs e)
        {

        }

        private void mnDetection_Click(object sender, EventArgs e)
        {

        }

        private void capture()
        {
            while (this.running)
            {
                this.pbTrain.Image = this.inspector.loadImage().ToBitmap();
                Thread.Sleep(100);
            }

            this.inspector.closeCam();
        }

        private void btCamera_Click(object sender, EventArgs e)
        {
            switch (this.mode)
            {
                case MODE_CAPTURE:
                    {
                        this.mode = MODE_OPEN_CAMERA;
                        this.btCamera.Text = "   Capture fusebox";

                        this.inspector.openCam();

                        if (this.camThread != null)
                        {
                            this.running = false;
                            this.camThread.Abort();
                            this.camThread = null;
                        }

                        this.running = true;
                        this.camThread = new Thread(new ThreadStart(capture));
                        this.camThread.Start();
                    }
                    break;
                case MODE_OPEN_CAMERA:
                    {
                        this.mode = MODE_CAPTURE;
                        this.btCamera.Text = "   Open Camera";

                        if (this.camThread != null)
                        {
                            this.running = false;
                        }

                        
                    }
                    break;
            }

        }

        private void pbTrain_MouseDown(object sender, MouseEventArgs e)
        {
            if (this.mode != MODE_CAPTURE)
                return;

            startPoint = e.Location;// this.pictureBox1.PointToClient(Cursor.Position);
            //startPoint.Offset(this.pictureBox1.Location);
            origBitmap = this.pbTrain.Image;
        }

        private void pbTrain_MouseLeave(object sender, EventArgs e)
        {
            if (this.mode != MODE_CAPTURE)
                return;

            startPoint = new Point(-1, -1);
        }

        private void pbTrain_MouseMove(object sender, MouseEventArgs e)
        {
            if (this.mode != MODE_CAPTURE)
                return;

            if (origBitmap == null || startPoint.Equals(new Point(-1, -1)))
                return;

            Image image = (Image)this.origBitmap.Clone();
            Graphics g = Graphics.FromImage(image);

            Point endPoint = this.pbTrain.PointToClient(Cursor.Position);

            this.currentRect = new Rectangle(startPoint.X, startPoint.Y, endPoint.X - startPoint.X, endPoint.Y - startPoint.Y);
            g.DrawRectangle(new Pen(new SolidBrush(Color.Red), 3.0f), this.currentRect);
            this.pbTrain.Image = image;
        }

        private void pbTrain_MouseUp(object sender, MouseEventArgs e)
        {
            if (this.mode != MODE_CAPTURE)
                return;
            
            DataRow dataRow = this.fuseTable.NewRow();
            dataRow["Position"] = this.currentRect;

            this.fuseTable.Rows.Add(dataRow);
            this.dgRectangles.DataSource = this.fuseTable;

            startPoint = new Point(-1, -1);
        }

        private void btSave_Click(object sender, EventArgs e)
        {
            string model = "";
            if (DialogResult.OK != InputBox("Please type the model", "Please type the model", ref model) ||
                model.Length == 0)
            {
                return;
            }

            prepareDirectory();

            FileStream file = File.Open(String.Format(FILE_SETTINGS, model), FileMode.Create);
            StreamWriter writer = new StreamWriter(file);

            foreach (DataRow row in this.fuseTable.Rows)
            {
                writer.Write(row["Position"]);
                writer.Write(":");
                writer.Write(row["Color"]);
                writer.Write(":");
                writer.Write(row["Ampere"]);
                writer.WriteLine();
            }

            writer.Close();
            file.Close();

            
        }

        public static DialogResult InputBox(string title, string promptText, ref string value)
        {
            Form form = new Form();
            System.Windows.Forms.Label label = new System.Windows.Forms.Label();
            TextBox textBox = new TextBox();
            Button buttonOk = new Button();
            Button buttonCancel = new Button();

            form.Text = title;
            label.Text = promptText;
            textBox.Text = value;

            buttonOk.Text = "OK";
            buttonCancel.Text = "Cancel";
            buttonOk.DialogResult = DialogResult.OK;
            buttonCancel.DialogResult = DialogResult.Cancel;

            label.SetBounds(9, 20, 372, 13);
            textBox.SetBounds(12, 36, 372, 20);
            buttonOk.SetBounds(228, 72, 75, 23);
            buttonCancel.SetBounds(309, 72, 75, 23);

            label.AutoSize = true;
            textBox.Anchor = textBox.Anchor | AnchorStyles.Right;
            buttonOk.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
            buttonCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;

            form.ClientSize = new Size(396, 107);
            form.Controls.AddRange(new Control[] { label, textBox, buttonOk, buttonCancel });
            form.ClientSize = new Size(Math.Max(300, label.Right + 10), form.ClientSize.Height);
            form.FormBorderStyle = FormBorderStyle.FixedDialog;
            form.StartPosition = FormStartPosition.CenterScreen;
            form.MinimizeBox = false;
            form.MaximizeBox = false;
            form.AcceptButton = buttonOk;
            form.CancelButton = buttonCancel;

            DialogResult dialogResult = form.ShowDialog();
            value = textBox.Text;
            return dialogResult;
        }


        private void prepareDirectory(){
            if (!Directory.Exists(DIR_SETTINGS))
            {
                Directory.CreateDirectory(DIR_SETTINGS);
            }
        }

        private void refreshModels()
        {
            this.cbModels.Items.Clear();

            string[] fileNames = Directory.GetFiles(DIR_SETTINGS);
            foreach (string fileName in fileNames)
            {
                this.cbModels.Items.Add(fileName);
            }
        }

        private void btRefreshModel_Click(object sender, EventArgs e)
        {
            refreshModels();
        }

        private void btCheck_Click(object sender, EventArgs e)
        {
            this.inspector.openCam();
            Image<Bgr,byte> image = this.inspector.loadImage().Copy();
            this.pbCheck.Image = (Bitmap) image.ToBitmap().Clone();
            
            this.inspector.closeCam();

            FileStream file = File.Open(this.cbModels.Text, FileMode.Open);
            StreamReader reader = new StreamReader(file);

            Bitmap bitmap = (Bitmap) this.pbCheck.Image.Clone();
            Graphics g = Graphics.FromImage(bitmap);
            Scanner scanner = new Scanner();
            int count = 0;
            String line = null;
            while((line = reader.ReadLine()) != null){
                string[] parts = line.Split(':');
                string rectText = parts[0];
                string color = parts[1];
                string ampere = parts[2];

                object[] targets = new object[4];
                targets[0] = new Int16();
                targets[1] = new Int16();
                targets[2] = new Int16();
                targets[3] = new Int16();

                parts[0] = parts[0].Replace("{", "").Replace("}", "").Replace("X=","").Replace("Y=","")
                    .Replace("Width=","").Replace("Height=","");

                string[] rparts = parts[0].Split(',');
                Rectangle rect = new Rectangle(
                    int.Parse(rparts[0]),
                    int.Parse(rparts[1]),
                    int.Parse(rparts[2]),
                    int.Parse(rparts[3]));

                
                Image<Bgr, byte> fuse = image.Copy(rect);
                fuse.SmoothBlur(20, 20);
                Image<Hsv, byte> fuseHsv = fuse.Convert<Hsv, byte>();
                Image<Gray, byte>[] csplits = fuseHsv.Split();
                Image<Gray, byte> cHue = csplits[0];

                MCvScalar val = CvInvoke.cvAvg(cHue, IntPtr.Zero);
                //MessageBox.Show(val.v0 + "");

                //fuse.Save(@"c:\" + (++count) + ".bmp");

                Color c = Color.Red;
                if (val.v0 > 115 && val.v0 < 160 && color.Equals("red"))
                {
                    c = Color.Green;
                }
                else if (val.v0 > 90 && val.v0 < 110 && color.Equals("blue"))
                {
                    c = Color.Green;
                }
                else if (val.v0 < 80 && color.Equals("yellow"))
                {
                    c = Color.Green;
                }

                count++;

                g.DrawRectangle(new Pen(new SolidBrush(c),2.0f), rect);
                g.DrawString(val.v0 + "", new Font(FontFamily.GenericSerif,7.0f,FontStyle.Bold), new SolidBrush(c), new PointF(rect.X, rect.Y));
                
            }

            this.pbCheck.Image = bitmap;

            reader.Close();
            file.Close();

            image.Dispose();
        }

        private void cbModels_SelectedIndexChanged(object sender, EventArgs e)
        {
            string text;
            text = cbModels.Text;
            Image<Bgr, byte> image = new  Image<Bgr,byte>(text);
            pbCheck.Image = (Bitmap)image.ToBitmap().Clone();
        }

        private void btOpenImage_Click(object sender, EventArgs e)
        {

        }

        private void cbImage_Click(object sender, EventArgs e)
        {
            this.cbModels.Items.Clear();
   
            string[] fileNames = Directory.GetFiles(DIR_SETTINGS);
            foreach (string fileName in fileNames)
            {
                this.cbImage.Items.Add(fileName);
            }
        }

        private void cbImage_SelectedIndexChanged(object sender, EventArgs e)
        {
            string text;
            int h, w;
            text = cbImage.Text;
            Image<Bgr, byte> image = new Image<Bgr, byte>(text);

            h = image.Size.Height;
            w = image.Size.Width;
            
            pbShow.Image = (Bitmap)image.ToBitmap().Clone();
            this.mmode = MMODE_CAPTURE;
        }

        private void pbShow_MouseDown(object sender, MouseEventArgs e)
        {
            if (this.mmode != MMODE_CAPTURE)
                return;
            S_Point = e.Location;
            BBitmap = new Image<Bgr, Byte>((Bitmap)this.pbShow.Image);
        }

        private void pbShow_MouseUp(object sender, MouseEventArgs e)
        {
            if (this.mmode != MMODE_CAPTURE)
                return;
            E_point = e.Location;
            if (((E_point.X - S_Point.X) > 0) || ((E_point.Y - S_Point.Y) > 0))
            {
                Rectangle rect = new Rectangle(S_Point.X, S_Point.Y, E_point.X - S_Point.X, E_point.Y - S_Point.Y);


                Image<Bgr, byte> Imgcrop = BBitmap.Copy(rect);
                pbSelect.Size = new Size(E_point.X - S_Point.X, E_point.Y - S_Point.Y);
                //pbSelect.Image = (Bitmap)Imgcrop.Bitmap.Clone();

                // Create and initialize histogram
                DenseHistogram histHue = new DenseHistogram(180, new RangeF(0.0f, 255.0f));
                // Convert RGB to HSV
                Image<Hsv, byte> imgHSV = Imgcrop.Convert<Hsv, byte>();
                Image<Gray, byte>[] channels = imgHSV.Split();
                Image<Gray, Byte> imgHue = channels[0];
                Image<Gray, Byte> imgSat = channels[1];
                Image<Gray, Byte> imgVal = channels[2];
                
                // Histogram Computing
                //histHue.Calculate<byte>(new Image<Gray, byte>[] { imgHue }, true, null);
              //  float value;
                //for(int count = 0; count < 180; count++){
                  //  value = (float)CvInvoke.cvQueryHistValue_1D(histHue.Ptr, count);
                    
               // }
                HistogramViewer.Show(imgHue);
                S_Point = new Point(-1, -1);
            }
        }

        private void pbShow_MouseLeave(object sender, EventArgs e)
        {
            if (this.mmode != MMODE_CAPTURE)
                return;
            S_Point = new Point(-1, -1);
        }

        private void pbShow_MouseMove(object sender, MouseEventArgs e)
        {
            if (this.mmode != MMODE_CAPTURE)
                return;
            if (BBitmap == null || S_Point.Equals(new Point(-1, -1)))
                return;
            E_point = e.Location;
            Image image = (Image)this.BBitmap.Bitmap.Clone();
            Graphics g = Graphics.FromImage(image);

           // Point endPoint = this.pbShow.PointToClient(Cursor.Position);

            this.currentRect = new Rectangle(S_Point.X, S_Point.Y, E_point.X - S_Point.X, E_point.Y - S_Point.Y);
            g.DrawRectangle(new Pen(new SolidBrush(Color.Red), 3.0f), this.currentRect);
            this.pbShow.Image = image;

            
        }

        private Capture labelCapture;

        private void startLabelMode()
        {
            this.labelCapture = new Capture(0);
            this.tmLabel.Start();
        }

        private void stopLabelMode()
        {
            this.labelCapture.Dispose();
        }

        private void tabControl1_TabIndexChanged(object sender, EventArgs e)
        {
            if (this.tabControl1.SelectedIndex == 0)
            {
                startLabelMode();
            }
            else
            {
                stopLabelMode();
            }
        }

        private MultiFormatReader m_BarcodeReader = new MultiFormatReader();

        private void tmLabel_Tick(object sender, EventArgs e)
        {
            Emgu.CV.Image<Bgr, byte> image = this.labelCapture.QueryFrame();
            Emgu.CV.Image<Gray, byte> gray = image.Convert<Gray, byte>();
            Bitmap capture = image.ToBitmap();
            this.pbLabel.Image = capture;

            Hashtable hints = new Hashtable();
            ArrayList fmts = new ArrayList();
            fmts.Add(BarcodeFormat.QR_CODE);

            Result rawResult;
            RGBLuminanceSource r = new RGBLuminanceSource(capture, capture.Width, capture.Height);
            GlobalHistogramBinarizer x = new GlobalHistogramBinarizer(r);
            BinaryBitmap bitmap = new BinaryBitmap(x);


            try
            {
                rawResult = m_BarcodeReader.decode(bitmap, hints);
                if (rawResult != null)
                {
                    lbModel.Text = rawResult.Text;
                    this.tabControl1.SelectedIndex = 1;
                    //MessageBox.Show(rawResult.Text);
                    this.tmLabel.Stop();
                }
            }
            catch (ReaderException ex)
            {
                
            }

            image.Dispose();
            gray.Dispose();
        }


     }
}
